// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/Forward Rendering"
{
    Properties
    {
        _MainTex("Main Texture", 2D) = "white" {}
        _RMapTex("RMap Texture", 2D) = "white" {}
        _Specular("Specular", Color) = (1,1,1,1)
        _RimColor("RimColor", Color) = (1,1,1,1)
        _RimPower("RimPow", Range(0, 10)) = 0.1 
        _RimIntensity("RimIntensity", Range(0.1, 10)) = 0.1
        _RimStep("RimStep", Range(0, 10)) = 0.1
        _Gloss("Gloss", Range(8,256)) = 8
    }

    SubShader
    {
        Pass
        {
            Tags
            {
                "LightMode" = "ForwardBase"
            }

            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #pragma multi_compile_fwdbase

            #include "UnityCg.cginc"
            #include "Lighting.cginc"
            #include "AutoLight.cginc"

            sampler2D _MainTex;
            sampler2D _RMapTex;
            fixed4 _Specular;
            float _Gloss;

            fixed4 _RimColor;
            float _RimPower;
            float _RimIntensity;
            float _RimStep;

            struct appdata
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
                float3 normal : NORMAL;
            };

            struct v2f
            {
                float4 pos : SV_POSITION;
                float2 uv : TEXCOORD0;
                float3 worldNormal : TEXCOORD1;
                float4 worldPos: TEXCOORD2;
                SHADOW_COORDS(3)
            };

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                o.worldNormal = UnityObjectToWorldNormal(v.normal);
                o.worldPos = mul(unity_ObjectToWorld, v.vertex);
                TRANSFER_SHADOW(o);
                return o;
            }


            // ----------------------------------------------------
            // @brief 兰伯特
            // @param[L] 灯光的方向
            // @param[V] 位置指向摄像机的方向
            // @param[N] 世界法线
            float Lambert(float3 L, float3 V, float3 N)
            {
                return max(0, dot(N, L));
            }
            // ----------------------------------------------------
            // @brief 半兰伯特
            // @param[L] 灯光的方向
            // @param[V] 位置指向摄像机的方向
            // @param[N] 世界法线
            float HalfLambert(float3 L, float3 V, float3 N)
            {
                return max(0, dot(N, L) * 0.5 + 0.5);
            }
            // ----------------------------------------------------
            // @brief 布林冯
            // @param[L] 灯光的方向
            // @param[V] 位置指向摄像机的方向
            // @param[N] 世界法线
            // @param[S] 光泽度
            float BlinnPhong(float3 L, float3 V, float3 N, float gloss)
            {
                float3 H = normalize(L+V);
                return pow(max(0,dot(N,H)), gloss);
            }
            // ----------------------------------------------------
            // @brief 冯
            // @param[L] 灯光的方向
            // @param[V] 位置指向摄像机的方向
            // @param[N] 世界法线
            // @param[S] 光泽度
            float Phong(float3 L, float3 V, float3 N, float gloss)
            {
                float3 R = normalize(reflect(-L, N));
                return pow(max(0,dot(R,V)), gloss);
            }
            // ----------------------------------------------------
            // @brief 冯修正
            // @param[L] 灯光的方向
            // @param[V] 位置指向摄像机的方向
            // @param[N] 世界法线
            // @param[S] 光泽度
            float ModifiedPhong(float3 L, float3 V, float3 N, float gloss)
            {
                float3 R = normalize(reflect(-L, N));
                float norm = (gloss+2)/(2*3.14159265358979323846);
                return norm * pow(max(0,dot(R,V)), gloss);
            }


            // ----------------------------------------------------
            // @brief 边缘光
            // @param[L] 灯光的方向
            // @param[V] 位置指向摄像机的方向
            // @param[N] 世界法线
            float Rim(float3 L, float3 V, float3 N,  float p, float intensity)
            {
                return pow(1.0 - max(0, dot(N, V)), p) * intensity;
            }




            fixed4 frag(v2f i) : SV_TARGET
            {
                fixed4 albedo = tex2D(_MainTex, i.uv);
                fixed4 ambient = albedo * UNITY_LIGHTMODEL_AMBIENT;

                
                float3 L = normalize(UnityWorldSpaceLightDir(i.worldPos.xyz));
                float3 V = normalize(UnityWorldSpaceViewDir(i.worldPos.xyz));
                float3 N = i.worldNormal;

                fixed4 diff = albedo * _LightColor0 * Lambert(L, V, N);

                fixed4 spec = albedo * _Specular * ModifiedPhong(L, V, N, _Gloss);

                // 边缘光
                float rim = Rim(L, V, N, _RimPower, _RimIntensity); 
                fixed4 rimColor = smoothstep(0, _RimStep, rim) * rim * _RimColor;

                
                // Rimlight
                float falloffU = clamp( 1.0 - abs( dot(N, V) ), 0.02, 0.98 );
                float rimlightDot = saturate( 0.5 * ( dot( N, L ) + 1.0 ) );
                falloffU = saturate( rimlightDot * falloffU );
                falloffU = tex2D(_RMapTex, float2( falloffU, 0.25f ) ).r;



                float shadow = SHADOW_ATTENUATION(i);
				fixed4 col = albedo * rimColor + albedo * falloffU + (spec) * shadow;
                return col;
            }

            ENDCG
        }
    }

    Fallback "VertexLit"
    
}